#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
HygonJDK 调优脚本: GC 日志分析 (第 3 节)
用法:
  cat gc.log | python3 analyze_gc.py
  python3 analyze_gc.py /path/to/gc.log
"""

import re
import sys
from collections import Counter

# 匹配 Full GC 及其原因 (JDK 9+ Unified Logging格式)
# 示例: [20.606s][info][gc] GC(2) Pause Full (System.gc()) 9M->8M(89424M) 19.920ms
RE_FULL_GC = re.compile(r'GC\(\d+\) Pause Full \((.+?)\) .*? ([\d.]+)ms')

# 匹配 Young GC (用于统计所有GC)
# 示例: [3.195s][info][gc] GC(0) Pause Young (Allocation Failure) 85664M->3M(89424M) 3.244ms
RE_GC_EVENT = re.compile(r'GC\(\d+\) Pause (\w+) \((.+?)\) .*? ([\d.]+)ms')

# 匹配 GCLocker Initiated GC
RE_GCLOCKER = re.compile(r'GCLocker Initiated GC', re.IGNORECASE)

# 匹配内存变化信息 (Before->After(Total))
RE_MEMORY_CHANGE = re.compile(r'(\d+)M->(\d+)M\((\d+)M\)')

# 匹配GC时间戳
RE_TIMESTAMP = re.compile(r'\[([\d.]+)s\]')

# 匹配GC吞吐量相关信息
RE_THROUGHPUT = re.compile(r'User=([\d.]+)s Sys=([\d.]+)s Real=([\d.]+)s')

def parse_gc_log(log_content):
    analysis = {
        "full_gcs": [],
        "all_gcs": [],
        "stw_times_ms": [],
        "triggers": Counter(),
        "gc_types": Counter(),
        "gclocker_count": 0,
        "memory_changes": [],
        "gc_timestamps": [],
        "throughput_info": []
    }

    lines = log_content.split('\n')
    
    for line in lines:
        # 1. 查找所有 GC 事件
        gc_match = RE_GC_EVENT.search(line)
        if gc_match:
            gc_type = gc_match.group(1)
            reason = gc_match.group(2)
            duration_ms = float(gc_match.group(3))
            
            # 查找内存变化信息
            memory_match = RE_MEMORY_CHANGE.search(line)
            memory_info = {}
            if memory_match:
                memory_info = {
                    "before_mb": int(memory_match.group(1)),
                    "after_mb": int(memory_match.group(2)),
                    "total_mb": int(memory_match.group(3))
                }
            
            # 查找时间戳
            timestamp_match = RE_TIMESTAMP.search(line)
            timestamp = float(timestamp_match.group(1)) if timestamp_match else 0
            
            gc_event = {
                "type": gc_type,
                "reason": reason,
                "duration_ms": duration_ms,
                "memory": memory_info,
                "timestamp": timestamp
            }
            
            analysis["all_gcs"].append(gc_event)
            analysis["gc_types"][gc_type] += 1
            
            # 如果是 Full GC，单独记录
            if gc_type == "Full":
                analysis["full_gcs"].append(gc_event)
                analysis["triggers"][reason] += 1
            
            analysis["stw_times_ms"].append(duration_ms)
            if timestamp > 0:
                analysis["gc_timestamps"].append(timestamp)

        # 2. 查找 GCLocker GC
        if RE_GCLOCKER.search(line):
            analysis["gclocker_count"] += 1

        # 3. 查找吞吐量信息
        throughput_match = RE_THROUGHPUT.search(line)
        if throughput_match:
            analysis["throughput_info"].append({
                "user_time": float(throughput_match.group(1)),
                "sys_time": float(throughput_match.group(2)),
                "real_time": float(throughput_match.group(3))
            })

    if analysis["gclocker_count"] > 0:
        analysis["triggers"]["GCLocker Initiated GC"] = analysis["gclocker_count"]

    return analysis

def print_gc_report(analysis):
    print("=" * 70)
    print("HygonJDK 调优助手 - GC 日志分析报告")
    print("=" * 70)

    # 1. Full GC 分析
    print("\n--- 1. Full GC 分析 (Section 3.3.1, 3.3.2) ---")
    full_gc_count = len(analysis["full_gcs"])
    
    if full_gc_count > 0:
        print(f"[\033[91m严重\033[0m] 在日志片段中检测到 {full_gc_count} 次 Full GC。")
        print("Full GC 触发原因统计:")
        for reason, count in analysis["triggers"].items():
            print(f"  - {reason:<25}: {count} 次")
            if reason == "System.gc()":
                print("    \033[93m建议\033[0m: 检查代码是否手动调用 System.gc()。可考虑 -XX:+DisableExplicitGC。")
            if reason == "Metadata GC Threshold":
                print("    \033[93m建议\033[0m: 元空间不足。检查类加载器泄漏或调大 -XX:MaxMetaspaceSize。")
            if reason == "GCLocker Initiated GC":
                 print("    \033[93m建议\033[0m: JNI 临界区代码持有锁时间过长, 导致 GC 等待。请检查 JNI 实现。")
    else:
        print("[\033[92m正常\033[0m] 在日志片段中未检测到 Full GC。")

    # 2. STW (Stop-The-World) 时长分析 (Section 3.3.3)
    print("\n--- 2. STW (Stop-The-World) 时长分析 ---")
    stw_times = analysis["stw_times_ms"]
    if not stw_times:
        print("[\033[94m信息\033[0m] 未能从日志中解析出 STW 时间。")
        print("=" * 70)
        return

    total_stw_count = len(stw_times)
    max_stw_ms = max(stw_times)
    avg_stw_ms = sum(stw_times) / total_stw_count
    long_stw_100ms = len([t for t in stw_times if t > 100]) # 超过 100ms
    long_stw_1s = len([t for t in stw_times if t > 1000])   # 超过 1s
    
    print(f"总 STW (所有GC) 次数: {total_stw_count}")
    
    color_max = "\033[92m" # 绿色
    if max_stw_ms > 1000:
        color_max = "\033[91m" # 红色
    elif max_stw_ms > 100:
        color_max = "\033[93m" # 黄色
    print(f"最大 STW 暂停: {color_max}{max_stw_ms:.2f} ms\033[0m")
    
    print(f"平均 STW 暂停: {avg_stw_ms:.2f} ms")
    print(f"超过 100ms 的暂停次数: \033[93m{long_stw_100ms}\033[0m")
    print(f"超过 1000ms (1s) 的暂停次数: \033[91m{long_stw_1s}\033[0m")
    
    if long_stw_1s > 0:
        print("[\033[91m严重\033[0m] 存在超过 1 秒的 STW 暂停, 会严重影响应用响应。")
    elif long_stw_100ms > 0:
        print("[\033[93m注意\033[0m] 存在超过 100ms 的 STW 暂停, 可能影响延时敏感型应用。")

    # 3. GC 类型分布分析
    print("\n--- 3. GC 类型分布分析 ---")
    if analysis["gc_types"]:
        print("GC 类型统计:")
        for gc_type, count in analysis["gc_types"].items():
            percentage = (count / total_stw_count) * 100
            print(f"  - {gc_type:<15}: {count} 次 ({percentage:.1f}%)")
    
    # 4. 内存使用分析
    print("\n--- 4. 内存使用分析 ---")
    memory_events = [gc for gc in analysis["all_gcs"] if gc.get("memory")]
    if memory_events:
        # 计算平均内存回收量
        total_reclaimed = 0
        for event in memory_events:
            memory = event["memory"]
            reclaimed = memory["before_mb"] - memory["after_mb"]
            total_reclaimed += reclaimed
        
        avg_reclaimed = total_reclaimed / len(memory_events) if memory_events else 0
        print(f"平均每次GC回收内存: {avg_reclaimed:.1f} MB")
        
        # 查找最大内存使用
        max_memory_usage = max([event["memory"]["before_mb"] for event in memory_events])
        print(f"最大内存使用量: {max_memory_usage} MB")
        
        # 分析内存回收效率
        if avg_reclaimed < 10:
            print("[\033[93m注意\033[0m] 内存回收效率较低，可能存在内存碎片或对象生命周期问题。")
    
    # 5. GC 吞吐量分析
    print("\n--- 5. GC 吞吐量分析 ---")
    if analysis["gc_timestamps"]:
        total_time = max(analysis["gc_timestamps"]) - min(analysis["gc_timestamps"])
        if total_time > 0:
            gc_time_percentage = (sum(stw_times) / 1000) / total_time * 100
            print(f"GC时间占比: {gc_time_percentage:.2f}%")
            
            if gc_time_percentage > 10:
                print("[\033[91m严重\033[0m] GC时间占比过高 (>10%)，严重影响应用吞吐量。")
            elif gc_time_percentage > 5:
                print("[\033[93m注意\033[0m] GC时间占比偏高 (>5%)，可能影响性能。")
            else:
                print("[\033[92m正常\033[0m] GC时间占比在可接受范围内。")
    
    # 6. 性能优化建议
    print("\n--- 6. 性能优化建议 ---")
    suggestions = []
    
    if full_gc_count > 0:
        suggestions.append("🔴 减少Full GC: 优化内存分配，避免大对象创建")
    
    if long_stw_100ms > 0:
        suggestions.append("🟡 降低STW时间: 考虑使用G1GC或ZGC等低延迟GC")
    
    if analysis["gclocker_count"] > 0:
        suggestions.append("🟡 减少GCLocker: 优化JNI代码，减少临界区持有时间")
    
    if not suggestions:
        suggestions.append("✅ 当前GC表现良好，继续保持当前配置")
    
    for suggestion in suggestions:
        print(f"  {suggestion}")

    print("=" * 70)

def main():
    try:
        if len(sys.argv) > 1:
            filepath = sys.argv[1]
            with open(filepath, 'r', encoding='utf-8') as f:
                log_content = f.read()
        else:
            log_content = sys.stdin.read()
            
        if not log_content:
            print("错误: 未提供日志内容。", file=sys.stderr)
            print(__doc__, file=sys.stderr)
            sys.exit(1)

        analysis = parse_gc_log(log_content)
        print_gc_report(analysis)

    except FileNotFoundError:
        print(f"错误: 文件未找到 {sys.argv[1]}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"发生错误: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
